package org.mozhu.mboot.core.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.PropertyResolver;
import org.springframework.core.env.PropertySources;
import org.springframework.core.env.PropertySourcesPropertyResolver;
import org.springframework.util.Assert;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;

@Slf4j
public class ApplicationConfiguration implements Configuration {

    private ApplicationConfiguration() {
    }

    private static class ApplicationConfigurationHolder {
        private static final ApplicationConfiguration INSTANCE = new ApplicationConfiguration();

        private ApplicationConfigurationHolder() {
        }
    }

    public static final ApplicationConfiguration get() {
        return ApplicationConfigurationHolder.INSTANCE;
    }

    private PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer;

    public void init(PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer) {
        Assert.notNull(propertySourcesPlaceholderConfigurer, "PropertySourcesPlaceholderConfigurer should not be null");
        this.propertySourcesPlaceholderConfigurer = propertySourcesPlaceholderConfigurer;
    }

    protected PropertyResolver getPropertyResolver() {
        Assert.notNull(propertySourcesPlaceholderConfigurer, "PropertySourcesPlaceholderConfigurer should not be null, ApplicationConfiguration may not init properly!");
        return new PropertySourcesPropertyResolver(this.propertySourcesPlaceholderConfigurer.getAppliedPropertySources());
    }

    protected PropertySources getPropertySources() {
        Assert.notNull(propertySourcesPlaceholderConfigurer, "PropertySourcesPlaceholderConfigurer should not be null, ApplicationConfiguration may not init properly!");
        return this.propertySourcesPlaceholderConfigurer.getAppliedPropertySources();
    }

    @Override
    public String getProperty(String name, String defaultValue) {
        return getPropertyResolver().getProperty(name, defaultValue);
    }

    @Override
    public String getProperty(String name) {
        return getPropertyResolver().getProperty(name);
    }

    @Override
    public void setProperty(String name, String value) {

    }

    @Override
    public Map<String, String> getProperties() {
        Map<String, String> result = new HashMap<>();
        Set<String> keys = getKeys();
        for (String key : keys) {
            result.put(key, getProperty(key));
        }
        return result;
    }

    private Set<String> getKeys() {
        return PropertiesUtils.getKeys(this.getPropertySources());
    }


    private List<ConfigurationListener> configurationListeners = new CopyOnWriteArrayList<>();

    public void addListener(ConfigurationListener listener) {
        configurationListeners.add(listener);
    }

    public List<ConfigurationListener> getConfigurationListeners() {
        return configurationListeners;
    }
}
